// =====================================================================
//
//  This file is part of the Microsoft Dynamics CRM SDK code samples.
//
//  Copyright (C) Microsoft Corporation.  All rights reserved.
//
//  This source code is intended only as a supplement to Microsoft
//  Development Tools and/or on-line documentation.  See these other
//  materials for detailed information regarding Microsoft code samples.
//
//  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//
// =====================================================================
using System;
using System.Collections.Generic;

namespace Microsoft.Xrm.Sdk
{
	/// <summary>
	/// Represents the enumeration that identifies the state of an entity being tracked by the <see cref="OrganizationServiceContext"/>.
	/// </summary>
	[Flags]
	internal enum EntityStates
	{
		Detached = 0x1,
		Unchanged = 0x2,
		Added = 0x4,
		Deleted = 0x8,
		Modified = 0x10,
	}

	internal abstract class Descriptor
	{
		public EntityStates State { get; set; }

		protected Descriptor(EntityStates state)
		{
			State = state;
		}
	}

	/// <summary>
	/// A container of entity changes performed by the <see cref="OrganizationServiceContext"/>.
	/// </summary>
	internal sealed class EntityDescriptor : Descriptor
	{
		public EntityReference Identity { get; private set; }
		public Entity Entity { get; private set; }

		public EntityDescriptor(EntityStates state, EntityReference identity, Entity entity)
			: base(state)
		{
			Identity = identity;
			Entity = entity;
		}
	}

	/// <summary>
	/// A container of relationship changes performed by the <see cref="OrganizationServiceContext"/>.
	/// </summary>
	internal sealed class LinkDescriptor : Descriptor
	{
		private class LinkDescriptorComparer : IEqualityComparer<LinkDescriptor>
		{
			public bool Equals(LinkDescriptor x, LinkDescriptor y)
			{
				if ((x == null) && (y == null))
					return true;

				return x != null && y != null
					&& Equals(x.Source, y.Source)
					&& Equals(x.Relationship, y.Relationship)
					&& Equals(x.Target, y.Target);
			}

			public int GetHashCode(LinkDescriptor obj)
			{
				if (obj == null) return 0;

				return ((obj.Source.GetHashCode() ^ ((obj.Target != null) ? obj.Target.GetHashCode() : 0)) ^ ((obj.Relationship != null) ? obj.Relationship.GetHashCode() : 0));
			}
		}

		internal static readonly IEqualityComparer<LinkDescriptor> EquivalenceComparer = new LinkDescriptorComparer();
		public Entity Source { get; private set; }
		public Relationship Relationship { get; private set; }
		public Entity Target { get; private set; }

		public LinkDescriptor(Entity source, Relationship relationship, Entity target)
			: this(EntityStates.Unchanged, source, relationship, target)
		{
		}

		public LinkDescriptor(EntityStates state, Entity source, Relationship relationship, Entity target)
			: base(state)
		{
			Source = source;
			Relationship = relationship;
			Target = target;
		}
	}
}
